/* ps-sdl2 --- Pre-Scheme wrappers for SDL2
**
** This header defines some C macros around the SDL2 API to make it
** usable from Pre-Scheme.  It's intended to be used via the ps-sdl2
** Pre-Scheme package.  Corresponding Pre-Scheme definitions can be
** found in "ps-sdl2.scm".
*/

#include <SDL2/SDL.h>
#include <stdlib.h>

#define DEFINE_STRUCT_WRAPPER(wrapper, actual)                  \
  struct wrapper;                                               \
  static inline struct wrapper* wrap_##wrapper(actual* ptr) {   \
    return (struct wrapper*)ptr;                                \
  }                                                             \
  static inline actual* unwrap_##wrapper(struct wrapper* ptr) { \
    return (actual*)ptr;                                        \
  }

DEFINE_STRUCT_WRAPPER(sdl_window, SDL_Window);
DEFINE_STRUCT_WRAPPER(sdl_renderer, SDL_Renderer);
DEFINE_STRUCT_WRAPPER(sdl_event, SDL_Event);

static inline struct sdl_window* PS_SDL_CreateWindow(const char* title,
                                                     long x, long y, long w, long h,
                                                     long flags) {
  return wrap_sdl_window(SDL_CreateWindow(title, x, y, w, h, flags));
}

static inline void PS_SDL_DestroyWindow(struct sdl_window* window) {
  SDL_DestroyWindow(unwrap_sdl_window(window));
}

static inline struct sdl_renderer* PS_SDL_CreateRenderer(struct sdl_window* window,
                                                         long index, long flags) {
  return wrap_sdl_renderer(SDL_CreateRenderer(unwrap_sdl_window(window), index, flags));
}

static inline void PS_SDL_DestroyRenderer(struct sdl_renderer* renderer) {
  SDL_DestroyRenderer(unwrap_sdl_renderer(renderer));
}

static inline long PS_SDL_SetRenderDrawColor(struct sdl_renderer* renderer,
                                             long r, long g, long b, long a) {
  return SDL_SetRenderDrawColor(unwrap_sdl_renderer(renderer), r, g, b, a);
}

static inline long PS_SDL_RenderClear(struct sdl_renderer* renderer) {
  return SDL_RenderClear(unwrap_sdl_renderer(renderer));
}

static inline void PS_SDL_RenderPresent(struct sdl_renderer* renderer) {
  SDL_RenderPresent(unwrap_sdl_renderer(renderer));
}

static inline long PS_SDL_RenderFillRect(struct sdl_renderer* renderer,
                                         long x, long y, long w, long h) {
  SDL_Rect rect = { x, y, w, h };
  return SDL_RenderFillRect(unwrap_sdl_renderer(renderer), &rect);
}

static inline struct sdl_event* PS_SDL_CreateEvent(void) {
  return wrap_sdl_event((SDL_Event*)calloc(1, sizeof(SDL_Event)));
}

static inline void PS_SDL_DestroyEvent(struct sdl_event* event) {
  free(unwrap_sdl_event(event));
}

static inline long PS_SDL_PollEvent(struct sdl_event* event) {
  return SDL_PollEvent(unwrap_sdl_event(event));
}

static inline long PS_SDL_EventType(struct sdl_event* event) {
  return unwrap_sdl_event(event)->type;
}
